<?php

/*
$File: class.wave.php
$Date: 09-02-08
*/

class Wave
{

    var $fp, $filesize;
    var $data, $blocktotal, $blockfmt, $blocksize;

    function __construct($file)
    {

        if (!$this->fp = @fopen($file, 'rb')) {
            return false;
        }

        $this->filesize = filesize($file);

    }

    function wavechunk()
    {

        rewind($this->fp);

        $riff_fmt = 'a4ID/VSize/a4Type';
        $riff_cnk = @unpack($riff_fmt, fread($this->fp, 12));

        if ($riff_cnk['ID'] != 'RIFF' || $riff_cnk['Type'] != 'WAVE') {
            return - 1;
        }

        $format_header_fmt = 'a4ID/VSize';
        $format_header_cnk = @unpack($format_header_fmt, fread($this->fp, 8));

        if ($format_header_cnk['ID'] != 'fmt ' || !in_array($format_header_cnk['Size'],
            array(16, 18))) {
            return - 2;
        }

        $format_fmt = 'vFormatTag/vChannels/VSamplesPerSec/VAvgBytesPerSec/vBlockAlign/vBitsPerSample' . ($format_header_cnk['Size'] ==
            18 ? '/vExtra' : '');
        $format_cnk = @unpack($format_fmt, fread($this->fp, $format_header_cnk['Size']));

        if ($format_cnk['FormatTag'] != 1) {
            return - 3;
        }

        if (!in_array($format_cnk['Channels'], array(1, 2))) {
            return - 4;
        }

        $fact_fmt = 'a4ID/VSize/Vdata';
        $fact_cnk = @unpack($fact_fmt, fread($this->fp, 12));

        if ($fact_cnk['ID'] != 'fact') {
            fseek($this->fp, ftell($this->fp) - 12);
        }

        $data_fmt = 'a4ID/VSize';
        $data_cnk = @unpack($data_fmt, fread($this->fp, 8));

        if ($data_cnk['ID'] != 'data') {
            return - 5;
        }

        if ($data_cnk['Size'] % $format_cnk['BlockAlign'] != 0) {
            return - 6;
        }

        $this->data = fread($this->fp, $data_cnk['Size']);
        $this->blockfmt = $format_cnk['Channels'] == 1 ? 'sLeft' : 'sLeft/sRight';

        $this->blocktotal = $data_cnk['Size'] / 4;
        $this->blocksize = $format_cnk['BlockAlign'];

        $return = array('Channels' => $format_cnk['Channels'], 'SamplesPerSec' => $format_cnk['SamplesPerSec'],
            'AvgBytesPerSec' => $format_cnk['AvgBytesPerSec'], 'BlockAlign' => $format_cnk['BlockAlign'],
            'BitsPerSample' => $format_cnk['BitsPerSample'], 'Extra' => isset($format_cnk['Extra']) ?
            $format_cnk['Extra'] : '', 'seconds' => ($data_cnk['Size'] / $format_cnk['AvgBytesPerSec']));

        return $return;

    }

    function waveimage($channel = 'Left', $width = 1000, $height = 300, $bgcolor =
        array(255, 255, 255), $cenlinecolor = array(180, 180, 180), $imgcolor = array(0,
        0, 0))
    {

        if (!$this->data) {
            if (!is_array($this->wavechunk())) {
                return false;
            }
        }

        $width = max(10, $width);
        $height = max(10, $height);

        $border = 1;
        $center = ($height - $border * 2) / 2;

        $num_merge = max(1, round($this->blocktotal / $width));
        $width = min($width, ceil($this->blocktotal / $num_merge));

        $max = $min = 0;
        $x = 1;

        $pixels = array();
        $wavetotal = 0;

        for ($i = 0; $i < $this->blocktotal; $i++) {
            $blocks[] = @unpack($this->blockfmt, substr($this->data, $i * 4, $this->
                blocksize));
        }

        if (!isset($blocks[0][$channel])) {
            return false;
        }

        for ($i = 0; $i < $this->blocktotal; ) {

            for ($j = 0; $j < $num_merge; $j++) {
                if (isset($blocks[$i + $j])) {
                    $wavetotal += $blocks[$i + $j][$channel];
                }
            }

            $y = round($wavetotal / ($j + 1));
            $pixels[] = array($x, $y);

            $max = max($max, $y);
            $min = min($min, $y);

            $x++;
            $i += $num_merge;
            $wavetotal = 0;

        }

        $maxblock = max(abs($max), abs($min));
        $zoom = $maxblock / $center;

        $im = imagecreate($width, $height);
        $background = imagecolorallocate($im, $bgcolor[0], $bgcolor[1], $bgcolor[2]);

        if ($cenlinecolor) {
            $cenline = imagecolorallocate($im, $cenlinecolor[0], $cenlinecolor[1], $cenlinecolor[2]);
            imageline($im, 1, $center, $width, $center, $cenline);
        }

        $color = imagecolorallocate($im, $imgcolor[0], $imgcolor[1], $imgcolor[2]);
        $y_old = 0;

        foreach ($pixels as $pixel) {

            $y = $center - round($pixel[1] / $zoom);
            imagesetpixel($im, $pixel[0], $y, $color);

            if ($pixel[0] > 1) {
                imageline($im, $pixel[0] - 1, $y_old, $pixel[0], $y, $color);
            }

            $y_old = $y;

        }

        return $im;

    }

}

?>